#ifndef GRID_H
#define GRID_H

#include "vertexbufferobject.h"
#include "camera.h"
#include "container.h"

class Grid
{
public:
    Grid(float start = 0.0f, float unitLength = 1.0f);
    virtual ~Grid();
    
    float getStart() const { return start; }
    void setStart(float start) { this->start = start; }
    
    float getUnitLength() const { return unitLength; }
    void setUnitLength(float unitLength) { this->unitLength = unitLength; }
    
    void drawVBOWithCamera(Camera& camera);
    void drawVAWithCamera(Camera& camera);
	void drawTextWithCamera(Camera& camera);
	
	float getHorizontalPosition() const { return horizontalPosition; }
	void setHorizontalPosition(float y) { horizontalPosition = y; }
	
	void reassignColors() { modified = true; }
	
protected:
    virtual void generateGrid(long units, long startUnit, long endUnit, long unitsPerGrid, float pixelsPerUnit);
    
protected:
    float start;
    float unitLength;
    VertexBufferObject* compiledGrid;
    
    GLenum mode;
    
    long lastStartUnit;
    long lastEndUnit;
    long lastUnits;
    long lastUnitsPerGrid;
    float lastStart;
    float lastUnitLength;

    bool renderGrid;
	bool modified;
	
	float horizontalPosition;
	
private:
	long lastFirstSecondaryGridUnit;
};

class ElementsGrid : public Grid, public PickContainer
{
public:
    ElementsGrid(float start = 0.0f, float unitLength = 1.0f);
    virtual ~ElementsGrid() {}
    
    void setScaling(Vec3f scaling) { SetVec3f(this->scaling, scaling); unitLength = scaling[0]; }

    void drawVBOWithCamera(Camera& camera);
    void drawVAWithCamera(Camera& camera);
    void drawTextWithCamera(Camera& camera);
    
    void addElement(Element* element);
    QVector<Element*> pickElementsWithRay(const Ray& ray) const;
    PackedVecColor* getElementVertices(Element* element);
    
    long getStartIndex() const;
    long getEndIndex() const;

protected:
    virtual void generateGrid(long units, long startUnit, long endUnit, long unitsPerGrid, float pixelsPerUnit);
    
protected:
    static float elementsGridMinimalWidth;
};

class ElementsDoubleList
{
public:
	ElementsDoubleList();
	~ElementsDoubleList();
	
	void setupLayoutWithCamera(Camera& camera);
	
    void drawVBOWithCamera(Camera& camera);
    void drawVAWithCamera(Camera& camera);
    void drawTextWithCamera(Camera& camera);
	
	float getLeftWidth() const { return leftWidth; }
	float getRightWidth() const { return rightWidth; }
	
	unsigned getMaxListSize() const { return (unsigned)lastMaxTextBoxes; }
	
	const QVector<Element*>& getLeftList() const { return leftList; }
	void setLeftList(const QVector<Element*>& leftList) { this->leftList = leftList; }
	const QVector<Element*>& getRightList() const { return rightList; }
	void setRightList(const QVector<Element*>& rightList) { this->rightList = rightList; }
	
	void setLeftHitsFirst(bool flag) { leftHitsFirst = flag; }
	void setRightHitsFirst(bool flag) { rightHitsFirst = flag; }
	
	Ray getElementsDoubleListRelativeRay(const Ray& ray) const;
	
	bool hit(const Ray& ray) const;
	Element* pickElementWithRay(const Ray& ray) const;
	
protected:
	const PackedVecColor* getFirstLeftVertices() const;
	const PackedVecColor* getFirstRightVertices() const;
	
protected:
	VertexBufferObject* compiledList;
	
	float padding;
	float leftWidth;
	float rightWidth;
	
	QVector<Element*> leftList;
	QVector<Element*> rightList;
	
	bool leftHitsFirst;
	bool rightHitsFirst;
	
private:
	float lastWorldHeight;
	float lastWorldTextWidth;
	float lastWorldTextHeight;
	float lastWorldTextBoxPadding;
	float lastMaxTextBoxes;
	float lastWorldLeftTextCenter;
	float lastWorldRightTextCenter;
	float lastWorldLeftBoundary;
	float lastWorldRightBoundary;
};

#endif // GRID_H
